package org.dromara.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.business.domain.Message;
import org.dromara.business.domain.Room;
import org.dromara.business.domain.bo.MessageBo;
import org.dromara.business.domain.vo.MessageVo;
import org.dromara.business.mapper.RoomMapper;
import org.dromara.business.service.MessageService;
import org.dromara.business.service.RoomService;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.system.domain.SysUser;
import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 系统消息Service业务层处理
 *
 * @author zlj
 * @date 2024-08-26
 */
@RequiredArgsConstructor
@Service
public class RoomServiceImpl extends ServiceImpl<RoomMapper, Room> implements RoomService {

    private final MessageService messageService;
    private final ISysUserService userService;
    private final ScheduledExecutorService scheduledExecutorService;

    @Override
    public List<Room> getRoomList() {
        Long userId = LoginHelper.getUserId();
        List<Room> list = this.lambdaQuery()
            .and(wrapper ->
                wrapper.and(qr -> qr.eq(Room::getBigUserId, userId).eq(Room::getBigRemove, 0))
                    .or(qr -> qr.eq(Room::getTinyUserId, userId).eq(Room::getTinyRemove, 0))).list();
        if (CollectionUtil.isNotEmpty(list)) {
            List<Long> ids = list.stream().map(t -> t.getBigUserId().equals(userId) ? t.getTinyUserId() : t.getBigUserId()).toList();
            List<SysUser> userList = userService.lambdaQuery().select(SysUser::getUserId, SysUser::getNickName, SysUser::getWxAvatar).in(SysUser::getUserId, ids).list();
            for (Room room : list) {
                //查询用户头像和昵称
                for (SysUser sysUser : userList) {
                    if (sysUser.getUserId().equals(room.getBigUserId()) || sysUser.getUserId().equals(room.getTinyUserId())) {
                        room.setNickName(sysUser.getNickName());
                        room.setWxAvatar(sysUser.getWxAvatar());
                        break;
                    }
                }
                room.setDate(DateUtil.format(room.getUpdateTime(), "MM-dd"));
                if (ObjectUtil.equals(room.getLastContentUserId(), userId) && ObjectUtil.equals(room.getIsRead(), 0)) {
                    room.setIsRead(0);
                } else {
                    room.setIsRead(1);
                }
            }
        }
        return list;
    }

    @Override
    public Boolean getUnRead() {
        return this.lambdaQuery().eq(Room::getIsRead, 0).eq(Room::getLastContentUserId, LoginHelper.getUserId()).exists();
    }

    @Override
    public void send(MessageBo bo) {
        //发送人id
        Long userId = LoginHelper.getUserId();
        //接收人id
        Long receiverId = bo.getReceiverId();
        //发送消息
        Message message = SpringUtils.getAopProxy(this).send(userId, receiverId, bo.getMessageContent());
        this.senIM(userId, message, receiverId);
    }

    @Override
    public MessageVo sendByRoomId(MessageBo bo) {
        //查询聊天房间
        Room room = this.lambdaQuery().eq(Room::getRoomId, bo.getRoomId()).one();
        if (ObjectUtil.isNull(room)) {
            throw new ServiceException("对话不存在");
        }
        //自己id
        Long userId = LoginHelper.getUserId();
        //对方id
        Long receiverId = room.getBigUserId().equals(userId) ? room.getTinyUserId() : room.getBigUserId();
        //发送消息
        Message message = SpringUtils.getAopProxy(this).send(userId, receiverId, bo.getMessageContent());
        this.senIM(userId, message, receiverId);
        //发送自己im消息
        SysUser user = userService.lambdaQuery().select(SysUser::getNickName, SysUser::getWxAvatar)
            .eq(SysUser::getUserId, userId).one();
        MessageVo messageVo = new MessageVo();
        messageVo.setIsMe(true);
        messageVo.setCreateTime(new Date());
        messageVo.setNickName(user.getNickName());
        messageVo.setWxAvatar(user.getWxAvatar());
        messageVo.setMessageContent(message.getMessageContent());
        messageVo.setRoomId(message.getRoomId());
        //改变对方房间删除状态
        long max = Math.max(userId, receiverId);
        long min = Math.min(userId, receiverId);
        if (ObjectUtil.equals(receiverId, max) && ObjectUtil.equals(room.getBigRemove(), 1)) {
            this.lambdaUpdate().set(Room::getBigRemove, 0).eq(Room::getRoomId, room.getRoomId()).update();
        } else if (ObjectUtil.equals(receiverId, min) && ObjectUtil.equals(room.getTinyRemove(), 1)) {
            this.lambdaUpdate().set(Room::getTinyRemove, 0).eq(Room::getRoomId, room.getRoomId()).update();
        }
        return messageVo;
    }

    /**
     * 发送IM
     */
    private void senIM(Long userId, Message message, Long receiverId) {
        SysUser sendUser = userService.lambdaQuery().select(SysUser::getNickName, SysUser::getWxAvatar)
            .eq(SysUser::getUserId, userId).one();

        Date createTime = message.getCreateTime();

        //发送对方im消息
        MessageVo messageVo2 = new MessageVo();
        messageVo2.setIsMe(false);
        messageVo2.setCreateTime(createTime);
        messageVo2.setNickName(sendUser.getNickName());
        messageVo2.setWxAvatar(sendUser.getWxAvatar());
        messageVo2.setMessageContent(message.getMessageContent());
        messageVo2.setRoomId(message.getRoomId());

        scheduledExecutorService.schedule(() -> {
            WebSocketUtils.sendMessage(receiverId, JSONUtil.toJsonStr(messageVo2));
        }, 1, TimeUnit.SECONDS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Message send(Long senderId, Long receiverId, String messageContent) {
        //查询是不是有聊天房间
        long max = Math.max(senderId, receiverId);
        long min = Math.min(senderId, receiverId);
        Room room = this.lambdaQuery().eq(Room::getBigUserId, max)
            .eq(Room::getTinyUserId, min).one();
        if (ObjectUtil.isNull(room)) {
            // 创建房间
            room = new Room();
            room.setBigUserId(max);
            room.setTinyUserId(min);
        }
        room.setUpdateTime(new Date());
        room.setLastContent(messageContent);
        room.setIsRead(0);
        room.setLastContentUserId(receiverId);
        this.saveOrUpdate(room);
        // 增加信息
        Message message = new Message();
        message.setRoomId(room.getRoomId());
        message.setSenderId(senderId);
        message.setReceiverId(receiverId);
        message.setMessageContent(messageContent);
        messageService.save(message);
        return message;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeRoom(Long roomId) {
        //查询房间
        Room room = this.getById(roomId);
        if (LoginHelper.getUserId().equals(room.getBigUserId())) {
            room.setBigRemove(1);
        } else {
            room.setTinyRemove(1);
        }
        if (room.getBigRemove() == 1 && room.getTinyRemove() == 1) {
            // 删除房间及信息
            messageService.lambdaUpdate().eq(Message::getRoomId, roomId).remove();
            return this.removeById(roomId);
        }
        // 更新房间信息
        return this.updateById(room);
    }

    @Override
    public IPage<MessageVo> getMsgList(Long roomId, PageQuery pageQuery) {
        IPage<Message> page = messageService.lambdaQuery().eq(Message::getRoomId, roomId)
            .orderByDesc(Message::getCreateTime).page(pageQuery.build());
        List<Message> records = page.getRecords();

        IPage<MessageVo> result = pageQuery.build();
        result.setTotal(page.getTotal());
        if (CollectionUtil.isNotEmpty(records)) {
            //倒序
            records.sort((o1, o2) -> o1.getCreateTime().compareTo(o2.getCreateTime()));
            Long userId = LoginHelper.getUserId();
            //查询用户头像和昵称
            SysUser me = userService.lambdaQuery().select(SysUser::getUserId, SysUser::getNickName, SysUser::getWxAvatar)
                .eq(SysUser::getUserId, userId).one();

            Message message = records.get(0);
            SysUser you = userService.lambdaQuery().select(SysUser::getUserId, SysUser::getNickName, SysUser::getWxAvatar)
                .eq(SysUser::getUserId, message.getSenderId().equals(userId) ? message.getReceiverId() : message.getSenderId()).one();
            List<MessageVo> list = new ArrayList<>(records.size());
            for (Message record : records) {
                MessageVo messageVo = new MessageVo();
                messageVo.setMessageContent(record.getMessageContent());
                messageVo.setCreateTime(record.getCreateTime());
                messageVo.setIsMe(record.getSenderId().equals(userId));
                messageVo.setNickName(messageVo.getIsMe() ? me.getNickName() : you.getNickName());
                messageVo.setWxAvatar(messageVo.getIsMe() ? me.getWxAvatar() : you.getWxAvatar());
                list.add(messageVo);
            }
            result.setRecords(list);
        }
        this.lambdaUpdate().eq(Room::getRoomId, roomId).eq(Room::getLastContentUserId, LoginHelper.getUserId()).set(Room::getIsRead, 1).update();
        return result;
    }


    @Override
    public Long getRoomId(Long receiverId) {
        Long userId = LoginHelper.getUserId();
        if (userId.equals(receiverId)) {
            throw new ServiceException("不能给自己发消息");
        }
        long max = Math.max(userId, receiverId);
        long min = Math.min(userId, receiverId);

        Room room = this.lambdaQuery().eq(Room::getBigUserId, max)
            .eq(Room::getTinyUserId, min).one();

        if (ObjectUtil.isNull(room)) {
            // 创建房间
            room = new Room();
            room.setBigUserId(max);
            room.setTinyUserId(min);
            room.setIsRead(1);
            this.save(room);
        } else if (ObjectUtil.equals(userId, max) && ObjectUtil.equals(room.getBigRemove(), 1)) {
            this.lambdaUpdate().set(Room::getBigRemove, 0).eq(Room::getRoomId, room.getRoomId()).update();
        } else if (ObjectUtil.equals(userId, min) && ObjectUtil.equals(room.getTinyRemove(), 1)) {
            this.lambdaUpdate().set(Room::getTinyRemove, 0).eq(Room::getRoomId, room.getRoomId()).update();
        }
        return room.getRoomId();
    }
}
